
/*
 * Copyright (c) 2024 iSoftStone Education Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "los_task.h"
#include "config_network.h"
#include "lwip/tcp.h"
#include "lwip/ip_addr.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include "lwip/inet_chksum.h"
#include "los_swtmr.h" // 添加定时器头文件

#define LOG_TAG "tcp"
int get_wifi_info(WifiLinkedInfo *info);

#define OC_SERVER_IP "192.168.223.143" // App端电脑ip
#define SERVER_PORT 9001               // app端电脑接口

#define BUFF_LEN 256

#define ROUTE_SSID "bba"
#define ROUTE_PASSWORD "lyj666147"

// 用于模式1和模式2的全局变量和定时器ID
static unsigned int g_mode1_timer_id;
static unsigned int g_mode2_timer_id;

// 模式1的定时器回调函数
void Mode1_DisinfectCallback(UINT32 arg)
{
    printf("[模式1] 烘干完成，现在开始消毒过程...\n");
    // 调用消毒函数
    disinfect_init(10);
    (void)arg; // 防止编译警告
}

// 模式2的定时器回调函数
void Mode2_DisinfectCallback(UINT32 arg)
{
    printf("[模式2] 烘干完成，现在开始消毒过程...\n");
    // 调用消毒函数
    disinfect_init(10);
    (void)arg; // 防止编译警告
}

int get_wifi_info(WifiLinkedInfo *info)
{
    int ret = -1;
    int gw, netmask;
    memset(info, 0, sizeof(WifiLinkedInfo));
    unsigned int retry = 15;
    while (retry)
    {
        if (GetLinkedInfo(info) == WIFI_SUCCESS)
        {
            if (info->connState == WIFI_CONNECTED)
            {
                if (info->ipAddress != 0)
                {
                    LZ_HARDWARE_LOGD(LOG_TAG, "rknetwork IP (%s)", inet_ntoa(info->ipAddress));
                    if (WIFI_SUCCESS == GetLocalWifiGw(&gw))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network GW (%s)", inet_ntoa(gw));
                    }
                    if (WIFI_SUCCESS == GetLocalWifiNetmask(&netmask))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network NETMASK (%s)", inet_ntoa(netmask));
                    }
                    if (WIFI_SUCCESS == SetLocalWifiGw())
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "set network GW");
                    }
                    if (WIFI_SUCCESS == GetLocalWifiGw(&gw))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network GW (%s)", inet_ntoa(gw));
                    }
                    if (WIFI_SUCCESS == GetLocalWifiNetmask(&netmask))
                    {
                        LZ_HARDWARE_LOGD(LOG_TAG, "network NETMASK (%s)", inet_ntoa(netmask));
                    }
                    ret = 0;
                    goto connect_done;
                }
            }
        }
        LOS_Msleep(1000);
        retry--;
    }

connect_done:
    return ret;
}

void parse(char *buf, int count){

    if (buf[0] == 'u' && buf[1] == 'p'){ 
        // 上升  up
        printf("开始上升!\n");
        motorup();
    }
    else if (buf[0] == 'd' && buf[1] == 'o'){ 
        // 下降  down
        printf("开始下降!\n");
        motordown();
    }
    else if (buf[0] == 'd' && buf[1] == 'r'){ 
        // 烘干   dry medium 6
        printf("开始烘干!\n");
        int dryTime = 0, dryLevel = 1;
        for (int i = 0; i < count; i++){ 
            // 读取时间
            if (buf[i] >= '0' && buf[i] <= '9')
                dryTime = dryTime * 10 + (buf[i] - '0');
        }
        printf("烘干时间!  %d", dryTime);
        //'low' 'medium' 'high'
        // 读取挡位
        if (buf[4] == 'l')
        { // 低档
            dryLevel = 1;
        }
        else if (buf[4] == 'm')
        { // 中档
            dryLevel = 2;
        }
        else
        { // 高档
            dryLevel = 3;
        }
        fan_heater_demo_init(dryLevel, dryTime * 60);
    }
    else if (buf[0] == 'd' && buf[1] == 'i')
    { // 消毒  disinfect 6
        printf("开始消毒!\n");
        int disinfectTime = 0;
        for (int i = 0; i < count; i++)
        {
            if (buf[i] >= '0' && buf[i] <= '9')
                disinfectTime = disinfectTime * 10 + (buf[i] - '0');
        }
        printf("消毒时间: %d\n", disinfectTime);
        disinfect_init(disinfectTime);
        // 消毒调用
    }
    else if (buf[0] == '1')
    { // 模式1   1
        printf("模式1: 先烘干后消毒!\n");

        // 设置烘干时间为20秒（此处可根据需要调整）
        int dryTime = 10;

        // 创建一个定时器，在烘干结束后自动启动消毒
        // 定时器时间设置为略长于烘干时间（多加1秒作为缓冲）
        UINT32 ret = LOS_SwtmrCreate(dryTime * 1000 + 1000,
                                     LOS_SWTMR_MODE_ONCE,
                                     Mode1_DisinfectCallback,
                                     &g_mode1_timer_id,
                                     0);
        if (ret != LOS_OK)
        {
            printf("[模式1] 创建定时器失败: 0x%x\n", ret);
        }
        else
        {
            // 启动定时器
            ret = LOS_SwtmrStart(g_mode1_timer_id);
            if (ret != LOS_OK)
            {
                printf("[模式1] 启动定时器失败: 0x%x\n", ret);
            }
            else
            {
                printf("[模式1] 定时器启动成功，将在烘干结束后自动开始消毒\n");
            }
        }

        // 先启动烘干功能
        fan_heater_demo_init(1, dryTime);
    }
    else if (buf[0] == '2')
    { // 模式2   2
        printf("模式2: 先烘干后消毒!\n");

        //  // 设置烘干时间为10秒（此处根据模式2调整）
        int dryTime = 10;

        // 先启动烘干功能
        fan_heater_demo_init(1, dryTime);
    }
    else if (buf[0] == 'p' && buf[1] == 'u')
    { // 上升暂停  pu
        printf("上升暂停!\n");
        motorstop();
    }
    else if (buf[0] == 'p' && buf[1] == 'd')
    { // 下降暂停  pd
        printf("下降暂停!\n");
        motorstop7();
    }
    else if (buf[0] == 'l')
    { // 童锁  lock
        printf("童锁!\n");
        EnableChildLock(true);
    }
    else if (buf[0] == 'u' && buf[1] == 'n')
    { // 解除童锁  unlock
        printf("解除童锁!\n");
        EnableChildLock(false);
    }
    else
    { // 停止  stop
        printf("停止!\n");
    }
    LOS_Msleep(200);
}

void tcp_server_msg_handle(int fd)
{
    char buf[BUFF_LEN]; // 接收缓冲区
    socklen_t client_addr_len;
    int cnt = 0, count;
    int client_fd;
    struct sockaddr_in client_addr = {0};

    printf("waitting for client connect...\n");
    /* 监听socket 此处会阻塞 */
    client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_addr_len);
    printf("[tcp server] accept <%s:%d>\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    while (1)
    {
        memset(buf, 0, BUFF_LEN);
        printf("-------------------------------------------------------\n");
        printf("[tcp server] waitting client msg\n");
        count = recv(client_fd, buf, BUFF_LEN, 0); // read是阻塞函数，没有数据就一直阻塞
        if (count == -1)
        {
            printf("[tcp server] recieve data fail!\n");
            LOS_Msleep(3000);
            break;
        }

        printf("[tcp server] rev client msg:%s\n", buf);
        memset(buf, 0, BUFF_LEN);
        sprintf(buf, "I have recieved %d bytes data! recieved cnt:%d", count, ++cnt);
        printf("[tcp server] send msg:%s\n", buf);
        send(client_fd, buf, strlen(buf), 0); // 发送信息给client
    }
    lwip_close(client_fd);
    lwip_close(fd);
}

int wifi_server(void *arg)
{
    int server_fd, ret;

    while (1)
    {
        server_fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4;SOCK_STREAM:TCP
        if (server_fd < 0)
        {
            printf("create socket fail!\n");
            return -1;
        }

        /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket，而经历TIME_WAIT的过程。*/
        int flag = 1;
        ret = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int));
        if (ret != 0)
        {
            printf("[CommInitTcpServer]setsockopt fail, ret[%d]!\n", ret);
        }

        struct sockaddr_in serv_addr = {0};
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // IP地址，需要进行网络序转换，INADDR_ANY：本地地址
        serv_addr.sin_port = htons(SERVER_PORT); // 端口号，需要网络序转换
        /* 绑定服务器地址结构 */
        ret = bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
        if (ret < 0)
        {
            printf("socket bind fail!\n");
            lwip_close(server_fd);
            return -1;
        }
        /* 监听socket 此处不阻塞 */
        ret = listen(server_fd, 64);
        if (ret != 0)
        {
            printf("socket listen fail!\n");
            lwip_close(server_fd);
            return -1;
        }
        printf("[tcp server] listen:%d<%s:%d>\n", server_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
        tcp_server_msg_handle(server_fd); // 处理接收到的数据
        LOS_Msleep(1000);
    }
}

void tcp_client_msg_handle(int fd, struct sockaddr *dst)
{
    socklen_t len = sizeof(*dst);

    int cnt = 0, count = 0;
    while (connect(fd, dst, len) < 0)
    {
        printf("connect server failed...%d\n", ++count);
        lwip_close(fd);
        LOS_Msleep(5000);
        fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4;SOCK_STREAM:TCP
    }

    while (1)
    {
        char buf[BUFF_LEN];
        sprintf(buf, "TCP TEST cilent send:%d", ++cnt);
        count = send(fd, buf, strlen(buf), 0); // 发送数据给server
        printf("------------------------------------------------------------\n");
        printf("[tcp client] send:%s\n", buf);
        printf("[tcp client] client sendto msg to server %d,waitting server respond msg!!!\n", count);
        memset(buf, 0, BUFF_LEN);
        count = recv(fd, buf, BUFF_LEN, 0); // 接收来自server的信息
        // count = lwip_read(fd, buf, BUFF_LEN);     //接收来自server的信息
        if (count == -1)
        {
            printf("[tcp client] recieve data fail!\n");
            LOS_Msleep(3000);
            break;
        }
        printf("[tcp client] rev:%s\n", buf);

        parse(buf, count);
    }
    lwip_close(fd);
}

int wifi_client(void *arg)
{
    int client_fd, ret;
    struct sockaddr_in serv_addr;

    while (1)
    {
        client_fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4;SOCK_STREAM:TCP
        if (client_fd < 0)
        {
            printf("create socket fail!\n");
            return -1;
        }

        /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket，而经历TIME_WAIT的过程。*/
        int flag = 1;
        ret = setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int));
        if (ret != 0)
        {
            printf("[CommInitTcpServer]setsockopt fail, ret[%d]!\n", ret);
        }

        memset(&serv_addr, 0, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = inet_addr(OC_SERVER_IP);
        serv_addr.sin_port = htons(SERVER_PORT);
        printf("[tcp client] connect:%d<%s:%d>\n", client_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));

        tcp_client_msg_handle(client_fd, (struct sockaddr *)&serv_addr);

        LOS_Msleep(1000);
    }

    return 0;
}

void wifi_process(void *args)
{
    unsigned int threadID_client, threadID_server;
    unsigned int ret = LOS_OK;

    WifiLinkedInfo info;

    uint8_t mac_address[6] = {0x00, 0xdc, 0xb6, 0x90, 0x00, 0x00};

    FlashInit();
    VendorSet(VENDOR_ID_WIFI_MODE, "STA", 3); // 配置为Wifi STA模式
    VendorSet(VENDOR_ID_MAC, mac_address,
              6); // 多人同时做该实验，请修改各自不同的WiFi MAC地址
    VendorSet(VENDOR_ID_WIFI_ROUTE_SSID, ROUTE_SSID, sizeof(ROUTE_SSID));
    VendorSet(VENDOR_ID_WIFI_ROUTE_PASSWD, ROUTE_PASSWORD,
              sizeof(ROUTE_PASSWORD));

    SetWifiModeOff();
    SetWifiModeOn();

    while (get_wifi_info(&info) != 0)
        ;

    CreateThread(&threadID_client, wifi_client, NULL, "client@ process");
    CreateThread(&threadID_server, wifi_server, NULL, "server@ process");
}

void wifi_tcp_example(void)
{
    unsigned int ret = LOS_OK;
    unsigned int thread_id;
    TSK_INIT_PARAM_S task = {0};
    printf("%s start ....\n", __FUNCTION__);

    task.pfnTaskEntry = (TSK_ENTRY_FUNC)wifi_process;
    task.uwStackSize = 10240;
    task.pcName = "wifi_process";
    task.usTaskPrio = 24;
    ret = LOS_TaskCreate(&thread_id, &task);
    if (ret != LOS_OK)
    {
        printf("Falied to create wifi_process ret:0x%x\n", ret);
        return;
    }
    printf("进入连接#####################################\n");
}

APP_FEATURE_INIT(wifi_tcp_example);
